﻿/*SharpConsole VirtualCMD module
 * Handles all CMD operations, chdir, CD, ect
 * This is where most changes will be made.
 * See HelpString for info on what is/needs to be done.
 * 
 * Original Author: Scott Ketelaar
 * Original Creation: 3/15/2011
 * 
 * Most Recent Update: 3/16/2011 by Scott Ketelaar
 */
//TODO: better arg processing
using System;
namespace SharpConsole
{
	#region XMLdata
	/// <summary>
	/// Contains methods for emulating the command line.
	/// </summary>
    #endregion
	internal class VirtualCMD
    {
        [System.Runtime.InteropServices.DllImport("kernel32.dll", EntryPoint = "SetSystemTime", SetLastError = true)]
        internal extern static bool Win32SetSystemTime(ref SystemTime sysTime);
        internal struct SystemTime
        {
            public ushort Year;
            public ushort Month;
            public ushort DayOfWeek;
            public ushort Day;
            public ushort Hour;
            public ushort Minute;
            public ushort Second;
            public ushort Millisecond;
        };

#region HelpString
        const string help = @"
ARGS		   Controls processing of arguments.
**ASSOC        Displays or modifies file extension associations.
**ATTRIB       Displays or changes file attributes.
BREAK          Sets or clears extended CTRL+C checking.
**BCDEDIT      Sets properties in boot database to control boot loading.
**CACLS        Displays or modifies access control lists (ACLs) of files.
**CALL         Calls one batch program from another.
CD             Displays the name of or changes the current directory.
**CHCP         Displays or sets the active code page number.
CHDIR          Displays the name of or changes the current directory.
**CHKDSK         Checks a disk and displays a status report.
**CHKNTFS      Displays or modifies the checking of disk at boot time.
CLS            Clears the screen.
CMD            Starts a new instance of the Windows command interpreter.
COLOR          Sets the default console foreground and background colors.
**COMP           Compares the contents of two files or sets of files.
**COMPACT      Displays or alters the compression of files on NTFS partitions.
**CONVERT      Converts FAT volumes to NTFS.  You cannot convert the
               current drive.
**COPY           Copies one or more files to another location.
DATE           Displays the date.
DEL            Deletes one or more files.
DIR            Displays a list of files and subdirectories in a directory.
**DISKCOMP     Compares the contents of two floppy disks.
**DISKCOPY     Copies the contents of one floppy disk to another. Depreciated, use XCOPY instead.
**DISKPART     Displays or configures Disk Partition properties.
**DOSKEY       Edits command lines, recalls Windows commands, and
               creates macros.
**DRIVERQUERY  Displays current device driver status and properties.
ECHO           Displays messages.
**ENDLOCAL     Ends localization of environment changes in a batch file.
ERASE          Deletes one or more files.
EXIT           Quits the CMD.EXE program (command interpreter).
**FC             Compares two files or sets of files, and displays the
               differences between them.
**FIND           Searches for a text string in a file or files.
**FINDSTR        Searches for strings in files.
**FOR          Runs a specified command for each file in a set of files.
**FORMAT       Formats a disk for use with Windows.
**FSUTIL       Displays or configures the file system properties.
**FTYPE        Displays or modifies file types used in file extension
               associations.
**GOTO         Directs the Windows command interpreter to a labeled line in
               a batch program.
**GPRESULT     Displays Group Policy information for machine or user.
**GRAFTABL     Enables Windows to display an extended character set in
               graphics mode.
HELP           Provides Help information for Windows commands.
**ICACLS       Display, modify, backup, or restore ACLs for files and
               directories.
**IF           Performs conditional processing in batch programs.
**LABEL          Creates, changes, or deletes the volume label of a disk.
MD             Creates a directory.
MKDIR          Creates a directory.
**MKLINK       Creates Symbolic Links and Hard Links
**MODE         Configures a system device.
**MORE         Displays output one screen at a time.
**MOVE           Moves one or more files from one directory to another
               directory.
**OPENFILES    Displays files opened by remote users for a file share.
**PATH         Displays or sets a search path for executable files.
**PAUSE        Suspends processing of a batch file and displays a message.
**POPD         Restores the previous value of the current directory saved by
               PUSHD.
**PRINT          Prints a text file.
**PROMPT         Changes the Windows command prompt.
**PUSHD        Saves the current directory then changes it.
**RD             Removes a directory.
**RECOVER      Recovers readable information from a bad or defective disk.
**REM          Records comments (remarks) in batch files or CONFIG.SYS.
**REN            Renames a file or files.
**RENAME         Renames a file or files.
**REPLACE        Replaces files.
**RMDIR          Removes a directory.
**ROBOCOPY       Advanced utility to copy files and directory trees
SET            Displays Windows environment variables.
**SETLOCAL     Begins localization of environment changes in a batch file.
**SC             Displays or configures services (background processes).
**SCHTASKS     Schedules commands and programs to run on a computer.
**SHIFT        Shifts the position of replaceable parameters in batch files.
**SHUTDOWN       Allows proper local or remote shutdown of machine.
**SORT         Sorts input.
**START          Starts a separate window to run a specified program or command.
**SUBST        Associates a path with a drive letter.
**SYSTEMINFO     Displays machine specific properties and configuration.
**TASKLIST       Displays all currently running tasks.
**TASKKILL       Kill or stop a running process or application.
**TIME           Displays or sets the system time.
**TITLE          Sets the window title for a CMD.EXE session.
**TREE         Graphically displays the directory structure of a drive or
               path.
**TYPE           Displays the contents of a text file.
**VER            Displays the Windows version.
**VERIFY       Tells Windows whether to verify that your files are written
               correctly to a disk.
**VOL            Displays a disk volume label and serial number.
**XCOPY          Copies files and directory trees.
**WMIC         Displays WMI information inside interactive command shell.

** Indicates unsupported command.
~ Indicates some portion of the command is unimplemented.";
#endregion
        internal static ConsoleColor FG;
        internal static ConsoleColor BG;

#region XMLdata
        /// <summary>
        /// Attempts to run a command using .NET framework
        /// </summary>
        /// <param name="cmd">The command to run</param>
        /// <param name="args">An array of args</param>
        /// <returns>True if the command ran/attempted to run, false if the command is not supported</returns>
        // Authors: Scott Ketelaar
        #endregion
        internal static bool DoCommand(string cmd,params string[] args)
        {
            try
            {
                switch (cmd.ToLower().Trim())
                {
                	case "args":
                		Args(args);
                		return true;
                    case "break":
                        Console.TreatControlCAsInput = !Console.TreatControlCAsInput;
                        Console.WriteLine("Extended CTRL C checking is set to: {0}", !Console.TreatControlCAsInput);
                        return true;
                 	           case "cd":
                    case "chdir":
                        CD(args[0]);
                        return true;
                    case "cls":
                        Console.Clear();
                        return true;
                    case "cmd":
                        MainProgram.ExecuteShell(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
                        return true;
                    case "color":
                        if (args.Length == 0) Color(""); else Color(args[0]);
                        return true;
                    case "date":
                        if (args.Length == 0)
                        {
                            Console.WriteLine("The current date is: {0}", DateTime.Now.ToShortDateString());
                        }
                        else
                        {
                            try
                            {
                                DateTime DT = DateTime.Parse(args[0]);
                                SystemTime ST = new SystemTime();
                                ST.Day = (ushort)DT.Day;
                                ST.Month = (ushort)DT.Month;
                                ST.Year = (ushort)DT.Year;
                                Win32SetSystemTime(ref ST);
                                int result = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
                                if (result !=0)
                                    throw new System.ComponentModel.Win32Exception(result);
                            }
                            catch (Exception DTex)
                            {
                                Console.WriteLine("Error while setting date: {0}", DTex.Message);
                            }
                        }
                        return true;
                    case "dir":
                        DIR();
                        return true;
                    case "echo":
                        Echo(args);
                        return true;
                    case "del":
                    case "delete":
                    case "erase":
                        DelFile(args[0]);
                        return true;
                    case "exit":
                        return true;
                    case "help":
                        ShowHelp();
                        return true;
                    case "mkdir":
                    case "md":
                    MK(args[0]);
                    return true;
                   case "rd":
                   case "rmdir":
                    RD(args);
                    return true;
                    case "runas":
                        RunAs(args);
                        return true;
                    case "scr":
                        try
                        {
                            Utils.ExcecuteCSfile(args[0], args.Length > 1 ? args[1] : "");
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("Error while running script: {0}", ex.Message);
                        }
                        return true;
                    case "tab":
                    	Tab(args);
                        return true;
                    case "type":
                        Type(args);
                        return true;
                    default:
                        return false;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return false;
            }
        }

        private static void Type(params string[] Args)
        {
            try
            { 
                if (Args.Length == 0) throw new ArgumentException("The syntax of the command is incorrect.");
            if (Array.IndexOf<string>(Args, "-?") >= 0)
            {
                Console.WriteLine(@"Displays the contents of a text file or files.

TYPE [drive:][path]filename");
                return;
            }

                using (System.IO.StreamReader Reader = new System.IO.StreamReader(Args[0]))
                {
                    Console.WriteLine(Reader.ReadToEnd());
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error reading file: {0}", ex.Message);
            }
        }

        private static void Tab(params string[] args) {
        	if (Array.IndexOf(args, "-t") >=0 || Array.IndexOf(args, "-T") >=0){
        	MainProgram.UseAdvTab = ! MainProgram.UseAdvTab;
        	return;
        	}
        	if (args.Length == 0)
        		Console.WriteLine("Use advanced tabs: {0}", MainProgram.UseAdvTab);
      
        }
        
        private static void RunAs(params string[] Args)
        {
            string user = "";
            string password = "";
            string domain = Environment.UserDomainName;
            string program = "";
            foreach (string S in Args)
            {
                if (S.ToLower().Contains("-user:")) {
                    user = S.Remove(0, 6);
                }
                if (!S.Contains("-"))
                    program = S;
            }
            if (user.Contains("@")) {
                domain = user.Split(new char[] {'@'})[1];
                user = user.Replace("@" + domain, "");
            }
            try {
            Console.WriteLine("Enter the password for {0}", user);
            password = Console.ReadLine();
            System.Security.SecureString sS = new System.Security.SecureString();
            foreach(char c in password)
            	sS.AppendChar(c);
            MainProgram.ExecuteShell(program, new string[] {}, false, user, sS);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {
                password = "";
            }

        }
        
        #region XMLdata
        /// <summary>
        /// Controls argument processing.
        /// </summary>
        /// <param name="options">The options to apply</param>
        // Authors: Scott Ketelaar
        #endregion
        private static void Args(params string[] options) {
        	if (options.Length == 0) {
        		Console.WriteLine("Normalize Switches: {0}\nWarn if unswitched arg: {1}\nAutocorrect unswitched args: {2}"
        		                  , MainProgram.NormSwitches, MainProgram.WarnArgs, MainProgram.AutoCorrectArgs);
        	}
        	if (Array.IndexOf(options, "-?") >= 0)
        		#region HelpString
        		Console.WriteLine(@"
Useage: ARGS [-N] [-W] [-A] [-?]

ARGS without any parameters prints the current configuration.

-N	Toggles normalizing of switches. When normalizing is enabled, '/T' would automatically be converted to '-T'. The only reason to disable this is for compatability with older programs, note this may break some features.
-W	Toggles the display of a WARNING message when unswitched parameters are detected. Also controls notification of Autocorrect.
-A	Toggles autocorrecting unswitched parameters. When enabled, 'DIR S' is automatically converted to 'DIR -S'
-?	Displays this help screen.");
        	#endregion
        	if (Array.IndexOf(options, "-N") >= 0 || Array.IndexOf(options, "-n") >= 0)
        		MainProgram.NormSwitches = !MainProgram.NormSwitches;
        	if (Array.IndexOf(options, "-W") >= 0 || Array.IndexOf(options, "-w") >= 0)
        		MainProgram.WarnArgs = !MainProgram.WarnArgs;
        	if (Array.IndexOf(options, "-A") >= 0 || Array.IndexOf(options, "-a") >= 0)
        		MainProgram.AutoCorrectArgs = !MainProgram.AutoCorrectArgs;
      
        }
        
        #region XMLdata
        /// <summary>
        /// Removes Directory
        /// </summary>
        /// <param name="path">The path to the directory to remove</param>
        // Authors: Scott Ketelaar 
        #endregion
        private static void RD(params string[] path) {

        	bool S = (path[0].ToLower().StartsWith("/s") || path[0].ToLower().StartsWith("-s ") ? true : false);
        	try {
        	          	System.IO.Directory.Delete(S ? path[1] : path[0], S);
        	} catch (Exception ex) {
        		Console.WriteLine(ex.Message);
        	}
        	
        }
        
        #region XMLdata
        /// <summary>
        /// Makes a directory
        /// </summary>
        /// <param name="path">The path, including the directory name.</param>
        // Authors: Scott Ketelaar
        #endregion
        private static void MK(params string[] path) {
        	try {
        		System.IO.Directory.CreateDirectory(path[0]);
        	} catch (Exception ex) {
        		Console.WriteLine(ex.Message);
        	}
        }
        
		#region XMLdata
/// <summary>
/// Displays help string.
/// </summary>
//Authors: Scott Ketelaar
#endregion
        private static void ShowHelp(params string[] args)
        {
            Console.WriteLine(help);
        }
        
        #region XMLdata
        /// <summary>
        /// Deletes a file.
        /// </summary>
        /// <param name="path">The path of the file to delete</param>
        // Authors: Scott Ketelaar
        #endregion
        private static void DelFile(params string[] path)
        {
            try
            {
                System.IO.File.Delete(path[0]);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
        
        #region XMLdata
        /// <summary>
        /// Prints a message to the screen
        /// </summary>
        /// <param name="args">The string to print</param>
        // Authors: Scott Ketelaar 
        #endregion
        private static void Echo(params string[] args)
        {
            string output = "";
            foreach (string s in args)
                output += s + " ";
            Console.WriteLine(output);
        }
        
        #region XMLdata
        /// <summary>
        /// Changes the color of the console
        /// </summary>
        /// <param name="args">A string containing the hex notation of the colors, in {BackgroundForegound} format/</param>
        // Authors: Scott Ketelaar 
        #endregion
        private static void Color(params string[] args)
        {
            if (args[0] == "")
            {
                Console.BackgroundColor = BG;
                Console.ForegroundColor = FG;
                return;
            }
            if (args[0] == "/?")
            {
                #region Color Help
                Console.WriteLine(@"Sets the default console foreground and background colors.

COLOR [attr]

  attr        Specifies color attribute of console output

Color attributes are specified by TWO hex digits -- the first
corresponds to the background; the second the foreground.  Each digit
can be any of the following values:

    0 = Black       8 = Gray
    1 = Blue        9 = Light Blue
    2 = Green       A = Light Green
    3 = Aqua        B = Light Aqua
    4 = Red         C = Light Red
    5 = Purple      D = Light Purple
    6 = Yellow      E = Light Yellow
    7 = White       F = Bright White

If no argument is given, this command restores the color to what it was
when CMD.EXE started.

Eample: 'COLOR fc' produces light red on bright white");
                #endregion
            }
            else if (args[0].Length != 0 && args[0].Length != 2)
            {
                Console.WriteLine("Invaild or too many arguments to: \"COLOR\"");
            }
            else
            {
                Console.BackgroundColor = GetColor(args[0][0].ToString());
                Console.ForegroundColor = GetColor(args[0][1].ToString());
            }
        }
        #region XMLdata
        /// <summary>
        /// Converts hex to ConsoleColor
        /// </summary>
        /// <param name="arg">A string containing the hex representation of the color</param>
        /// <returns>A ConsoleColor equivalent to the hex argument, or black if an error occured.</returns>
        // Authors: Scott Ketelaar
        #endregion
        private static ConsoleColor GetColor(string arg)
        {
            switch (arg.ToLower().Trim())
            {
                case "0":
                    return ConsoleColor.Black;
                case "1":
                    return ConsoleColor.DarkBlue;
                case "2":
                    return ConsoleColor.DarkGreen;
                case "3":
                    return ConsoleColor.DarkCyan;
                case "4":
                    return ConsoleColor.DarkRed;
                case "5":
                    return ConsoleColor.DarkMagenta;
                case "6":
                    return ConsoleColor.DarkYellow;
                case "7":
                    return ConsoleColor.Gray;
                case "8":
                    return ConsoleColor.DarkGray;
                case "9":
                    return ConsoleColor.Blue;
                case "a":
                    return ConsoleColor.Green;
                case "b":
                    return ConsoleColor.Cyan;
                case "c":
                    return ConsoleColor.Red;
                case "d":
                    return ConsoleColor.Magenta;
                case "e":
                    return ConsoleColor.Yellow;
                case "f":
                    return ConsoleColor.White;
                default:
                    throw new ArgumentException("Hex value out of range!");
            }
        }
        
        #region XMLdata
        /// <summary>
        /// Chnges the current directory
        /// </summary>
        /// <param name="dir">The path to change the directory to.</param>
        // Authors: Scott Ketelaar
        #endregion
        private static void CD(params string[] dir)
        {
            if (dir[0] == "")
            {
                Console.WriteLine("Current directory: {0}", Environment.CurrentDirectory);
                return;
            }
            try
            {
                Environment.CurrentDirectory = dir[0];
                Console.WriteLine("Current directory is now {0}", Environment.CurrentDirectory);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
        
        #region XMLdata
        /// <summary>
        /// Prints a list of all files and folders in the current directory
        /// </summary>
        // Authors: Scott Ketelaar
        #endregion
        private static void DIR(params string[] args)
        {
            try
            {
                Console.WriteLine("----Folders in: " + Environment.CurrentDirectory + "----");
                foreach (string d in System.IO.Directory.GetDirectories(Environment.CurrentDirectory))
                    Console.WriteLine(d);
                Console.WriteLine("\n----Files in: " + Environment.CurrentDirectory + "----");
                foreach (string f in System.IO.Directory.GetFiles(Environment.CurrentDirectory))
                    Console.WriteLine(System.IO.Path.GetFileName(f));
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}